﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Web.Helpers;
using DotNetOpenAuth.AspNet.Clients;
using DotNetOpenAuth.Messaging;
using WebSiteFool.Libs;

namespace WebSiteFool.Clients
{
    public class SinaClient : OAuth2Client
    {
        #region Constants and Fields

        private const string _authorizationEndpoint = "https://api.weibo.com/oauth2/authorize";

        private const string _tokenEndpoint = "https://api.weibo.com/oauth2/access_token";

        private const string _userDataEndPoint = "https://api.weibo.com/2/users/show.json?";


        private readonly string _appId;
        private readonly string _appSecret;

        private string _uid;

        #endregion

        #region Constructors and Destructors

        public SinaClient(string appId, string appSecret)
            : this("sina", appId, appSecret)
        {
        }

        protected SinaClient(string providerName, string appId, string appSecret)
            : base(providerName)
        {
            this._appId = appId;
            this._appSecret = appSecret;
        }

        #endregion

        protected string AppId
        {
            get { return this._appId; }
        }

        #region Methods

        protected override Uri GetServiceLoginUrl(Uri returnUrl)
        {
            var builder = new UriBuilder(_authorizationEndpoint);
            builder.AppendQueryArgument("client_id", this._appId);
            builder.AppendQueryArgument("response_type", "code");
            builder.AppendQueryArgument("redirect_uri", returnUrl.AbsoluteUri);

            return builder.Uri;
        }

        protected override IDictionary<string, string> GetUserData(string accessToken)
        {
            SinaClientUserData sinaData;
            var request =
                WebRequest.Create(
                    _userDataEndPoint + "access_token=" + accessToken + "&uid=" + _uid);
            using (var response = request.GetResponse())
            {
                using (var responseStream = response.GetResponseStream())
                {
                    using (var streamReader = new StreamReader(responseStream))
                    {
                        var json = streamReader.ReadToEnd();
                        sinaData = Json.Decode<SinaClientUserData>(json);
                    }
                }
            }

            var userData = new Dictionary<string, string>();
            userData.AddItemIfNotEmpty("id", sinaData.Id);
            userData.AddItemIfNotEmpty("username", sinaData.ScreenName);
            userData.AddItemIfNotEmpty("name", sinaData.ScreenName);
            return userData;
        }

        protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            var entity = "client_id=" + this._appId + "&redirect_uri=" + returnUrl.AbsoluteUri + "&client_secret=" + this._appSecret + "&code=" + authorizationCode + "&grant_type=authorization_code";

            WebRequest tokenRequest = WebRequest.Create(_tokenEndpoint);
            tokenRequest.ContentType = "application/x-www-form-urlencoded";
            tokenRequest.ContentLength = entity.Length;
            tokenRequest.Method = "POST";

            using (Stream requestStream = tokenRequest.GetRequestStream())
            {
                var writer = new StreamWriter(requestStream);
                writer.Write(entity);
                writer.Flush();
            }

            HttpWebResponse tokenResponse = (HttpWebResponse)tokenRequest.GetResponse();
            if (tokenResponse.StatusCode == HttpStatusCode.OK)
            {
                using (Stream responseStream = tokenResponse.GetResponseStream())
                {
                    using (var streamReader = new StreamReader(responseStream))
                    {
                        var json = streamReader.ReadToEnd();
                        var tokenData = Json.Decode<SinaAccessTokenData>(json);
                        if (tokenData != null)
                        {
                            _uid = tokenData.Uid;
                            return tokenData.AccessToken;
                        }
                    }
                }
            }
            return null;
        }

        #endregion
    }
}